package com.song.yunpicturebackend.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.song.yunpicturebackend.exception.BusinessException;
import com.song.yunpicturebackend.exception.ErrorCode;
import com.song.yunpicturebackend.exception.ThrowUtils;
import com.song.yunpicturebackend.model.dto.space.SpaceAddRequest;
import com.song.yunpicturebackend.model.entity.Space;
import com.song.yunpicturebackend.mapper.SpaceMapper;
import com.song.yunpicturebackend.model.entity.User;
import com.song.yunpicturebackend.model.enums.SpaceLevelEnum;
import com.song.yunpicturebackend.service.SpaceService;
import com.song.yunpicturebackend.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.PostMapping;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* @author Administrator
* @description 针对表【space(空间)】的数据库操作Service实现
* @createDate 2025-01-06 19:54:43
*/
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
    implements SpaceService {

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private UserService userService;


    /**
     * 校验空间数据
     * @param space
     * @param add
     */
    @Override
    public void validSpace(Space space, boolean add) {
        ThrowUtils.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        //从对象中取值
        String spaceName = space.getSpaceName();
        Integer spaceLevel = space.getSpaceLevel();
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        //创建时
        if (add) {
            if (StrUtil.isBlank(spaceName)){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称不能为空");
            }
            if (spaceLevel == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不能为空");
            }
        }
        //修改数据时，如果要改空间时
        if (spaceLevel != null && spaceLevelEnum == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不存在");
        }
        if (StrUtil.isNotBlank(spaceName) && spaceName.length() > 30){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称过长");
        }
    }

    /**
     * 根据传入的空间级别自动分配空间大小
     * @param space
     */
    @Override
    public void fillSpaceBySpaceLevel(Space space) {
        //根据空间级别，自动填充限额
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(space.getSpaceLevel());
        if (spaceLevelEnum != null){
            Long maxSize = spaceLevelEnum.getMaxSize();
            if (space.getMaxCount() == null){
                space.setMaxCount(maxSize);
            }
            Long maxCount = spaceLevelEnum.getMaxCount();
            if (space.getMaxCount() == null){
                space.setMaxCount(maxCount);
            }
        }
    }

    Map<Long, Object> lockMap = new ConcurrentHashMap<>();

    /**
     * 新增空间
     * @param spaceAddRequest
     * @param loginUser
     * @return
     */
    @Override
    public long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        //此处将实体类和DTO进行转换
        Space space = new Space();
        BeanUtils.copyProperties(spaceAddRequest, space);
        //默认值
        if (StrUtil.isBlank(spaceAddRequest.getSpaceName())){
            space.setSpaceName("默认空间");
        }
        if (spaceAddRequest.getSpaceLevel() == null){
            space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
        }
        //填充数据
        this.fillSpaceBySpaceLevel(space);
        //校验数据
        this.validSpace(space, true);
        Long userId = loginUser.getId();
        space.setUserId(userId);
        //权限校验
        if (SpaceLevelEnum.COMMON.getValue() != spaceAddRequest.getSpaceLevel() && !userService.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限指定空间级别");
        }
        //针对用户加锁---1、对字符串常量池加锁，但是数据并不会及时释放
//        String lock = String.valueOf(userId).intern();
//        synchronized (lock){
//            Long newSpaceId = transactionTemplate.execute(status -> {
//                boolean exist = this.lambdaQuery().eq(Space::getUserId, userId).exists();
//                ThrowUtils.throwIf(exist, ErrorCode.OPERATION_ERROR, "每个用户只能有一个私有空间");
//                //写入数据库
//                boolean result = this.save(space);
//                if (!result) {
//                    throw new BusinessException(ErrorCode.OPERATION_ERROR);
//                }
//                //返回新写入的数据ID
//                return space.getId();
//            });
//            //返回结果包装类，可以做一些处理
//            return Optional.ofNullable(newSpaceId).orElse(-1L);
//        }
        //2、采用ConcurrentHashMap存储锁对象
        Object lock = lockMap.computeIfAbsent(userId, key -> new Object());
        synchronized (lock){
            try {
                Long newSpaceId = transactionTemplate.execute(status -> {
                    boolean exist = this.lambdaQuery().eq(Space::getUserId, userId).exists();
                    ThrowUtils.throwIf(exist, ErrorCode.OPERATION_ERROR, "每个用户只能有一个私有空间");
                    //写入数据库
                    boolean result = this.save(space);
                    if (!result) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR);
                    }
                    //返回新写入的数据ID
                    return space.getId();
                });
                //返回结果包装类，可以做一些处理
                return Optional.ofNullable(newSpaceId).orElse(-1L);
            } finally {
                lockMap.remove(userId);
            }
        }
    }
}




